package net.ufrog.common.xls;

import net.ufrog.common.exception.ServiceException;
import net.ufrog.common.utils.Strings;
import net.ufrog.common.xls.disposer.Disposer;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

/**
 * @author ultrafrog
 * @version 1.0, 2014-07-20
 * @since 1.0
 */
public class Excels {

    /** 构造函数 */
    private Excels() {}

    /**
     * 读取输入流
     *
     * @param is 输入流
     * @param requiredType 请求类型
     * @return 数据列表
     */
    public static <T extends Serializable> List<T> read(InputStream is, Class<T> requiredType) {
        Parser parser = Parser.get(requiredType);
        List<T> list = new ArrayList<>();
        try (Workbook workbook = WorkbookFactory.create(is)) {
            Sheet sheet = Strings.empty(parser.getSheetName()) ? workbook.getSheetAt(parser.getSheetIndex()) : workbook.getSheet(parser.getSheetName());
            sheet.forEach(row -> {
                if (row.getRowNum() >= parser.getSheetLabels()) {
                    try {
                        T data = requiredType.newInstance();
                        parser.getCells().forEach((k, v) -> {
                            try {
                                k.set(data, Disposer.get(row.getCell(v.index()), v, k.getType()));
                            } catch (IllegalAccessException e) {
                                throw new ServiceException(e.getMessage(), e);
                            }
                        });
                        list.add(data);
                    } catch (InstantiationException | IllegalAccessException e) {
                        throw new ServiceException(e.getMessage(), e);
                    }
                }
            });
            return list;
        } catch (IOException | InvalidFormatException e) {
            throw new ServiceException("cannot parse xls file.", e);
        }
    }

    /**
     * 写入输出流
     *
     * @param list 数据列表
     * @param os 输出流
     * @param requiredType 请求类型
     * @param <T> 请求泛型
     */
    public static <T extends Serializable> void write(List<T> list, OutputStream os, Class<T> requiredType) {
        Parser parser = Parser.get(requiredType);
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = Strings.empty(parser.getSheetName()) ? workbook.createSheet() : workbook.createSheet(parser.getSheetName());

            IntStream.range(0, parser.getSheetLabels() + list.size()).forEach(idx -> {
                Row row = sheet.createRow(idx);
                parser.getCells().forEach((k, v) -> {
                    Cell cell = row.createCell(v.index());
                    Object value;
                    Class<?> type = (idx < parser.getSheetLabels()) ? String.class : k.getType();

                    if (idx < parser.getSheetLabels()) {
                        value = (idx < v.value().length) ? v.value()[idx] : "";
                    } else {
                        try {
                            T data = list.get(idx - parser.getSheetLabels());
                            k.setAccessible(true);
                            value = k.get(data);
                        } catch (IllegalAccessException e) {
                            throw new ServiceException(e.getMessage() ,e);
                        }
                    }
                    Disposer.set(cell, value, v, type);
                });
            });
            workbook.write(os);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }
}
